package cz.proks.schoolpupilbook.gae.dao;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;

import com.google.appengine.api.datastore.KeyFactory;

import cz.proks.schoolpupilbook.gae.converter.Converter;
import cz.proks.schoolpupilbook.gae.converter.CourseConverter;
import cz.proks.schoolpupilbook.gae.converter.MarkConverter;
import cz.proks.schoolpupilbook.gae.converter.UserConverter;
import cz.proks.schoolpupilbook.gae.converter.UserCourseRelationConverter;
import cz.proks.schoolpupilbook.gae.converter.UserRelationConverter;
import cz.proks.schoolpupilbook.gae.dao.PersistenceManager.PersistenceExecutor;
import cz.proks.schoolpupilbook.gae.dbo.CourseDBO;
import cz.proks.schoolpupilbook.gae.dbo.MarkDBO;
import cz.proks.schoolpupilbook.gae.dbo.UserCourseRelationDBO;
import cz.proks.schoolpupilbook.gae.dbo.UserDBO;
import cz.proks.schoolpupilbook.gae.dbo.UserRelationDBO;
import cz.proks.schoolpupilbook.shared.domain.Course;
import cz.proks.schoolpupilbook.shared.domain.Mark;
import cz.proks.schoolpupilbook.shared.domain.User;
import cz.proks.schoolpupilbook.shared.domain.User.Role;
import cz.proks.schoolpupilbook.shared.domain.UserCourseRelation;
import cz.proks.schoolpupilbook.shared.domain.UserRelation;
import cz.proks.schoolpupilbook.shared.util.Tester;

public class ListDAO {
	private final Converter<UserDBO, User> userConverter = new UserConverter();
	private final Converter<CourseDBO, Course> courseConverter = new CourseConverter();
	private final Converter<MarkDBO, Mark> markConverter = new MarkConverter();
	private final Converter<UserCourseRelationDBO, UserCourseRelation> userCourseRelationConverter = new UserCourseRelationConverter();
	private final Converter<UserRelationDBO, UserRelation> userRelationConverter = new UserRelationConverter();
	
	@SuppressWarnings("unchecked")
	public List<User> listUsersByRole(final Role role) {
		final List<User> users = new LinkedList<User>();
		
		if (role == null)
			return users;
		
		return PersistenceManager.execute(new PersistenceExecutor<List<User>>() {
			
			@Override
			public List<User> doExecute(EntityManager em) {				
				List<UserDBO> dboList = new LinkedList<UserDBO>();
				
				 try {
					 dboList = em.createQuery("SELECT FROM " + UserDBO.class.getName() + " WHERE userRole = :userRole")
					   			.setParameter("userRole", role)
					  		    .getResultList();					 
				 } catch (NoResultException e) { }
				 
				 dboList = dboList == null ? new LinkedList<UserDBO>() : dboList;
				 				 
				 
				 for(UserDBO dbo : dboList) {
					 users.add(userConverter.getDomain(dbo));
				 }
				
				 return users;
			}
		}, false);
	}
	
	public List<Course> listCoursesForUser(final User user) {
		return listCoursesForUser(user == null ? null : user.getId());
	}
	
	@SuppressWarnings("unchecked")
	public List<Course> listCoursesForUser(final String userId) {
		final List<Course> courses = new LinkedList<Course>();
		
		if (userId == null)
			return courses;
		
		return PersistenceManager.execute(new PersistenceExecutor<List<Course>>() {
			
			@Override
			public List<Course> doExecute(EntityManager em) {				
				List<UserCourseRelationDBO> dboList = new LinkedList<UserCourseRelationDBO>();
				
				 try {
					 dboList = em.createQuery("SELECT FROM " + UserCourseRelationDBO.class.getName() + " WHERE userKey = :userKey")
					   			.setParameter("userKey", KeyFactory.stringToKey(userId))
					  		    .getResultList();					 
				 } catch (NoResultException e) { }
				 
				 dboList = dboList == null ? new LinkedList<UserCourseRelationDBO>() : dboList;				 				 
				 
				 for(UserCourseRelationDBO dbo : dboList) {
					 courses.add(userCourseRelationConverter.getDomain(dbo).getCourse());
				 }
				
				 return courses;
			}
		}, false);
	}
			
	public List<User> listUsersForCourse(final Course course) {
		return listUsersForCourse(course == null ? null : course.getId());
	}
	
	@SuppressWarnings("unchecked")
	public List<User> listUsersForCourse(final String courseId) {
		final List<User> students = new LinkedList<User>();
		
		if (courseId == null)
			return students;
		
		return PersistenceManager.execute(new PersistenceExecutor<List<User>>() {
			
			@Override
			public List<User> doExecute(EntityManager em) {				
				List<UserCourseRelationDBO> dboList = new LinkedList<UserCourseRelationDBO>();
				
				 try {
					 dboList = em.createQuery("SELECT FROM " + UserCourseRelationDBO.class.getName() + " WHERE courseKey = :courseKey")
					   			.setParameter("courseKey", KeyFactory.stringToKey(courseId))
					  		    .getResultList();					 
				 } catch (NoResultException e) { }
				 
				 dboList = dboList == null ? new LinkedList<UserCourseRelationDBO>() : dboList;				 				 
				 
				 for(UserCourseRelationDBO dbo : dboList) {
					 students.add(userCourseRelationConverter.getDomain(dbo).getUser());
				 }
				
				 return students;
			}
		}, false);
	}
		
	public List<Mark> listMarksForCourseAndUser(final User user, final Course course) {
		return listMarksForCourseAndUser(user == null ? null : user.getId(), course == null ? null : course.getId());
	}
	
	@SuppressWarnings("unchecked")
	public List<Mark> listMarksForCourseAndUser(final String userId, final String courseId) {
		final List<Mark> marks = new LinkedList<Mark>();
		
		if (Tester.isEmpty(userId) || Tester.isEmpty(courseId))
			return marks;
		
		return PersistenceManager.execute(new PersistenceExecutor<List<Mark>>() {
			
			@Override
			public List<Mark> doExecute(EntityManager em) {				
				List<MarkDBO> dboList = new LinkedList<MarkDBO>();
				
				 try {
					 dboList = em.createQuery("SELECT FROM " + MarkDBO.class.getName() + " WHERE studentKey = :studentKey AND courseKey = :courseKey")
					   			.setParameter("studentKey", KeyFactory.stringToKey(userId))
					 			.setParameter("courseKey", KeyFactory.stringToKey(courseId))
					  		    .getResultList();					 
				 } catch (NoResultException e) { }
				 
				 dboList = dboList == null ? new LinkedList<MarkDBO>() : dboList;				 				 
				 
				 for(MarkDBO dbo : dboList) {
					 marks.add(markConverter.getDomain(dbo));
				 }
				
				 return marks;
			}
		}, false);
	}
		
	public List<User> listUsersForParent(final User parent) {
		return listUsersForParent(parent == null ? null : parent.getId());
	}

	@SuppressWarnings("unchecked")	
	public List<User> listUsersForParent(final String parentId) {
		final List<User> students = new LinkedList<User>();
		
		if (parentId == null)
			return students;
		
		return PersistenceManager.execute(new PersistenceExecutor<List<User>>() {
			
			@Override
			public List<User> doExecute(EntityManager em) {				
				List<UserRelationDBO> dboList = new LinkedList<UserRelationDBO>();
				
				 try {
					 dboList = em.createQuery("SELECT FROM " + UserRelationDBO.class.getName() + " WHERE parentKey = :parentKey")
					   			.setParameter("parentKey", KeyFactory.stringToKey(parentId))
					  		    .getResultList();					 
				 } catch (NoResultException e) { }
				 
				 dboList = dboList == null ? new LinkedList<UserRelationDBO>() : dboList;				 				 
				 
				 for(UserRelationDBO dbo : dboList) {
					 students.add(userRelationConverter.getDomain(dbo).getStudent());
				 }
				
				 return students;
			}
		}, false);
	}
}
